<?php

class View_Discuz {

	const Ext = '.phtml';
	private $_scriptPath;
	private $_viewPath;

	var $tpl_var_regexp = "\#([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\-\>\[\]\'\"\$\.\x7f-\xff]+)";

	public function __construct() {
		$this->_scriptPath = ROOT_PATH . '/tmp';
		Shell::mkDir($this->_scriptPath);
	}

	public function display($tpl) {
		require_once $this->parse($tpl);
		exit;
	}

	private function parse($tpl) {
		$this->_viewPath = Run::getInstance()->GetAppPath() . './views/';
		$tplFile = $this->_viewPath . $tpl . self::Ext;
		$prefix = '';
		if (defined('PLUGIN_PATH')) {
			$prefix = PLUGIN_ID . '_' . VER_ID . '_';
		}
		$scriptFile = $this->_scriptPath . '/' . $prefix . str_replace('/', '_', $tpl) . self::Ext;

		$checkTime = @filemtime($scriptFile);
		if ($checkTime && $checkTime >= @filemtime($tplFile)) {
			return $scriptFile;
		}

		$template = '';
		if ($fp = @fopen($tplFile, 'r')) {
			$template = @fread($fp, filesize($tplFile));
			fclose($fp);
		}
		if (!$template) {
			throw new Exception("template load error");
		}

		$var_regexp = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\-\>)?[a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)";
		$const_regexp = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";

		$template = preg_replace("/([\n\r]+)\t+/s", "\\1", $template);
		$template = preg_replace("/\{$this->tpl_var_regexp}/s", "<?=\$this->\\1?>", $template);
		$template = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $template);
		$template = preg_replace_callback("/[\n\r\t]*\{eval\}\s*(\<\!\-\-)*(.+?)(\-\-\>)*\s*\{\/eval\}[\n\r\t]*/is", array($this, 'parse_template_callback_evaltags_2'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{eval\s+(.+?)\s*\}[\n\r\t]*/is", array($this, 'parse_template_callback_evaltags_1'), $template);
		$template = preg_replace("/\{(\\\$[a-zA-Z0-9_\-\>\[\]\'\"\$\.\x7f-\xff]+)\}/s", "<?=\\1?>", $template);
		$template = preg_replace_callback("/$var_regexp/s", array($this, 'parse_template_callback_addquote_1'), $template);
		$template = preg_replace_callback("/\<\?\=\<\?\=$var_regexp\?\>\?\>/s", array($this, 'parse_template_callback_addquote_1'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_echo1'), $template);
		$template = preg_replace_callback("/([\n\r\t]*)\{if\s+(.+?)\}([\n\r\t]*)/is", array($this, 'parse_template_callback_stripvtags_if123'), $template);
		$template = preg_replace_callback("/([\n\r\t]*)\{elseif\s+(.+?)\}([\n\r\t]*)/is", array($this, 'parse_template_callback_stripvtags_elseif123'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{uri\s+(.+?)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_echo2'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{api_uri\s+(.+?)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_echo3'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{api_static_uri\s+(.+?)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_echo4'), $template);
		$template = preg_replace("/\{else\}/i", "<? } else { ?>", $template);
		$template = preg_replace("/\{\/if\}/i", "<? } ?>", $template);

		$template = preg_replace_callback("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_loop12'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_loop123'), $template);
		$template = preg_replace("/\{\/loop\}/i", "<? } ?>", $template);

		$template = preg_replace("/\{$const_regexp\}/s", "<?=\\1?>", $template);
		if (!empty($this->_replacecode)) {
			$template = str_replace($this->_replacecode['search'], $this->_replacecode['replace'], $template);
		}

		$template = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $template);

		$template = preg_replace_callback("/\"(http)?[\w\.\/:]+\?[^\"]+?&[^\"]+?\"/", array($this, 'parse_template_callback_transamp_0'), $template);
		$template = preg_replace_callback("/\<script[^\>]*?src=\"(.+?)\"(.*?)\>\s*\<\/script\>/is", array($this, 'parse_template_callback_stripscriptamp_12'), $template);
		$template = preg_replace("/\<\?(\s{1})/is", "<?php\\1", $template);
		$template = preg_replace_callback("/[\n\r\t]*\{template\s+([a-z0-9_:\/]+)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_template1'), $template);
		$template = preg_replace_callback("/[\n\r\t]*\{template\s+(.+?)\}[\n\r\t]*/is", array($this, 'parse_template_callback_stripvtags_template1'), $template);
		$template = preg_replace("/\<\?\=(.+?)\?\>/is", "<?php echo \\1;?>", $template);
		$head = '<?php /* Last Compile ' . date('Y-m-d H:i:s') . " By Wit/View_Discuz */ ?>\n";
		if (!@$fp = fopen($scriptFile, 'w')) {
			throw new Exception("template script write error");
		}

		flock($fp, 2);
		fwrite($fp, $head . $template);
		fclose($fp);

		return $scriptFile;
	}

	function parse_template_callback_evaltags_1($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->evaltags($matches[1]);
	}

	function parse_template_callback_evaltags_2($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->evaltags($matches[2]);
	}

	function parse_template_callback_addquote_1($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->addquote('<?=' . $matches[1] . '?>');
	}

	function parse_template_callback_stripvtags_template1($matches) {
		return $this->loadtempate($matches[1]);
	}

	function parse_template_callback_stripvtags_echo1($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->stripvtags('<? echo ' . $matches[1] . '; ?>');
	}

	function parse_template_callback_stripvtags_echo2($matches) {
		return $this->stripvtags('<? echo Common::getURI(\'' . $matches[1] . '\'); ?>');
	}

	function parse_template_callback_stripvtags_echo3($matches) {
		return $this->stripvtags('<? echo Common::getAPIURI(\'' . $matches[1] . '\'); ?>');
	}

	function parse_template_callback_stripvtags_echo4($matches) {
		return $this->stripvtags('<? echo Common::getAPIStaticURI(\'' . $matches[1] . '\'); ?>');
	}

	function loadtempate($tpl) {
		return $this->stripvtags('<?php require_once $this->parse(\'' . $tpl . '\'); ?>');
	}

	function parse_var($v) {
		return preg_replace("/$this->tpl_var_regexp/s", "\$this->\\1", $v);
	}

	function parse_template_callback_stripvtags_if123($matches) {
		$matches[2] = $this->parse_var($matches[2]);
		return $this->stripvtags($matches[1] . '<? if(' . $matches[2] . ') { ?>' . $matches[3]);
	}

	function parse_template_callback_stripvtags_elseif123($matches) {
		$matches[2] = $this->parse_var($matches[2]);
		return $this->stripvtags($matches[1] . '<? } elseif(' . $matches[2] . ') { ?>' . $matches[3]);
	}

	function parse_template_callback_stripvtags_loop12($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->stripvtags('<? if(is_array(' . $matches[1] . ')) foreach(' . $matches[1] . ' as ' . $matches[2] . ') { ?>');
	}

	function parse_template_callback_stripvtags_loop123($matches) {
		$matches[1] = $this->parse_var($matches[1]);
		return $this->stripvtags('<? if(is_array(' . $matches[1] . ')) foreach(' . $matches[1] . ' as ' . $matches[2] . ' => ' . $matches[3] . ') { ?>');
	}

	function parse_template_callback_transamp_0($matches) {
		return $this->transamp($matches[0]);
	}

	function parse_template_callback_stripscriptamp_12($matches) {
		return $this->stripscriptamp($matches[1], $matches[2]);
	}

	function addquote($var) {
		return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
	}

	function evaltags($php) {
		$i = isset($this->_replacecode['search']) ? count($this->_replacecode['search']) : 0;
		$this->_replacecode['search'][$i] = $search = "<!--EVAL_TAG_$i-->";
		$this->_replacecode['replace'][$i] = "<? $php?>";
		return $search;
	}

	function stripvtags($expr, $statement = '') {
		$expr = str_replace('\\\"', '\"', preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr));
		$statement = str_replace('\\\"', '\"', $statement);
		return $expr . $statement;
	}

	function transamp($str) {
		$str = str_replace('&', '&amp;', $str);
		$str = str_replace('&amp;amp;', '&amp;', $str);
		return $str;
	}

	function stripscriptamp($s, $extra) {
		$s = str_replace('&amp;', '&', $s);
		return "<script src=\"$s\" type=\"text/javascript\"$extra></script>";
	}

	public function assign($name, $value = NULL) {
		if (is_array($name)) {
			foreach ($name as $k => $v) {
				$this->$k = $v;
			}
		} else {
			$this->$name = $value;
		}
		return true;
	}
}